'Copyright (c) 2008, Jonathan Allen

Imports System.Runtime.CompilerServices
Imports System.Net
Imports ClrExtensions.Security
Imports ClrExtensions.Security.OAuth
Imports ClrExtensions.Net.Rest

''' <summary>
''' The NetflixConnection object collects the information and implements the functions needed to make RESTful requests to the Netflix API servers.
''' </summary>
Public Class NetflixConnection
    Private ReadOnly m_ConsumerKey As String
    Private ReadOnly m_ConsumerSecret As String
    Private ReadOnly m_Catalog As Catalog

    ''' <summary>
    ''' The Consumer Secret assigned by Netflix to the application.
    ''' </summary>
    ''' <value>
    ''' 
    ''' </value>
    ''' <returns>
    ''' The application's Consumer Secret.
    ''' </returns>
    ''' <remarks>
    ''' The OAuth Consumer Secret is issued by Netflix once per application developer.
    ''' </remarks>
    Public ReadOnly Property ConsumerSecret() As String
        Get
            Return m_ConsumerSecret
        End Get
    End Property

    ''' <summary>
    ''' The Consumer Key assigned by Netflix to the application.
    ''' </summary>
    ''' <value>
    ''' 
    ''' </value>
    ''' <returns>
    ''' The application's Consumer Key.
    ''' </returns>
    ''' <remarks>
    ''' The OAuth Consumer Key is issued by Netflix once per application developer.
    ''' </remarks>
    Public ReadOnly Property ConsumerKey() As String
        Get
            Return m_ConsumerKey
        End Get
    End Property

    ''' <summary>
    ''' Creates a new instance of the NetflixConnection object, using the application's Consumer Key and Consumer Secret.
    ''' </summary>
    ''' <param name="consumerKey">
    ''' The Consumer Key assigned by Netflix to the application.
    ''' </param>
    ''' <param name="consumerSecret">
    ''' The Consumer Secret assigned by Netflix to the application.
    ''' </param>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Public Sub New(ByVal consumerKey As String, ByVal consumerSecret As String)
        m_ConsumerKey = consumerKey
        m_ConsumerSecret = consumerSecret
        m_Catalog = New Catalog(Me)
    End Sub

    ''' <summary>
    ''' Generates an OAuth Request Token and the Netflix strings needed for the current user to authenticate to the Netflix API.
    ''' </summary>
    ''' <exception cref="NetflixException">
    ''' 
    ''' </exception>
    ''' <returns>
    ''' A RequestToken object for the current user, which includes the OAuth Request Token, OAuth Request Secret, Netflix API-required application_name and login_url.
    ''' </returns>
    ''' <remarks>
    ''' This token includes a URL that the end user can use to approve your application. Once the application is approved, the Request Token can be used to obtain an Access Token.
    ''' </remarks>
    Public Function GenerateRequestToken() As RequestToken
        Dim fullRequest = NetflixUrls.GetRequestToken().SignRestCall(ConsumerKey, ConsumerSecret)

        Dim request = fullRequest.CreateHttpWebRequest
        Try
            Dim response = request.GetResponse
            Dim data = New IO.StreamReader(response.GetResponseStream).ReadToEnd
            Return New RequestToken(data, Me)
        Catch ex As Net.WebException
            Throw NetflixException.ParseException(ex)
        End Try
    End Function

    ''' <summary>
    ''' Converts an authorized Request Token into a user-specific Access Token.
    ''' </summary>
    ''' <param name="requestToken">
    ''' The RequestToken object returned from GenerateRequestToken().
    ''' </param>
    ''' <returns>
    ''' An Access Token specific to the current user.
    ''' </returns>
    ''' <remarks>
    ''' Do not call this method until after the user approves your application (which will authorize the Request Token). Calling it too soon will prevent Netflix from authorizing the Request Token.
    ''' </remarks>
    <Obsolete("Use RequestToken.ConvertToAccessToken")> Public Function GenerateAccessToken(ByVal requestToken As RequestToken) As AccessToken
        Return ConvertRequestToAccessToken(requestToken)
    End Function

    ''' <summary>
    ''' Converts an authorized Request Token into a user-specific Access Token.
    ''' </summary>
    ''' <param name="requestToken">
    ''' The RequestToken object returned from GenerateRequestToken().
    ''' </param>
    ''' <returns>
    ''' An Access Token specific to the current user.
    ''' </returns>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Friend Function ConvertRequestToAccessToken(ByVal requestToken As RequestToken) As AccessToken
        Dim fullRequest = NetflixUrls.GetAccessToken().SignRestCall(ConsumerKey, ConsumerSecret, requestToken.Token, requestToken.TokenSecret)
        Dim request = fullRequest.CreateHttpWebRequest
        Try
            Dim response = request.GetResponse
            Dim data = New IO.StreamReader(response.GetResponseStream).ReadToEnd
            Return New AccessToken(data)

        Catch ex As Net.WebException
            Throw NetflixException.ParseException(ex)
        End Try
    End Function

    ''' <summary>
    ''' This method performs a general Netflix request for the RESTful resource specified and returns the result as a stream.
    ''' </summary>
    ''' <param name="resource">
    ''' The RESTful resource being requested.
    ''' </param>
    ''' <returns>
    ''' An IO.StreamReader stream object containing the results of the RESTful resource request.
    ''' </returns>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Public Function RequestResourceStream(ByVal resource As RestCall) As IO.StreamReader
        Dim fullRequest = resource.SignRestCall(ConsumerKey, ConsumerSecret)

        Dim request = fullRequest.CreateHttpWebRequest
        Try
            Dim response = request.GetResponse
            Return New IO.StreamReader(response.GetResponseStream)
        Catch ex As Net.WebException
            Throw NetflixException.ParseException(ex)
        End Try
    End Function

    ''' <summary>
    ''' This method performs a general Netflix request for the RESTful resource specified and returns the results as a string.
    ''' </summary>
    ''' <param name="resource">
    ''' The RESTful resource being requested.
    ''' </param>
    ''' <returns>
    ''' A string containing the results of the RESTful resource request.
    ''' </returns>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Public Function RequestResource(ByVal resource As RestCall) As String
        Dim fullRequest = resource.SignRestCall(ConsumerKey, ConsumerSecret)

        Dim request = fullRequest.CreateHttpWebRequest

        Try
            Dim response = request.GetResponse
            Dim data = New IO.StreamReader(response.GetResponseStream).ReadToEnd
            Return data

        Catch ex As Net.WebException
            Throw NetflixException.ParseException(ex)
        End Try
    End Function

    '''' <summary>
    '''' This method performs a general Netflix request for the RESTful resource specified, signed with a user's token, and returns the results as a string.
    '''' </summary>
    '''' <param name="resource">
    '''' The RESTful resource being requested.
    '''' </param>
    '''' <param name="user">
    '''' 
    '''' </param>
    '''' <returns>
    '''' A string containing the results of the RESTful resource request.
    '''' </returns>
    '''' <remarks></remarks>
    'Public Function RequestResource(ByVal resource As RestCall, ByVal user As User) As String
    '       Return RequestResource(resource, user)
    'End Function

    ''' <summary>
    ''' ''' This method performs a general Netflix request, signed with a user's token, for the RESTful resource specified and returns the results as a string.
    ''' </summary>
    ''' <param name="resource">
    ''' The RESTful resource being requested.
    ''' </param>
    ''' <param name="accessToken">
    ''' The current user's Access Token.
    ''' </param>
    ''' <returns>
    ''' An IO.StreamReader stream object containing the results of the RESTful resource request.
    ''' </returns>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Public Function RequestResource(ByVal resource As RestCall, ByVal accessToken As IAccessToken) As String
        Dim fullRequest = resource.SignRestCall(ConsumerKey, ConsumerSecret, accessToken.Token, accessToken.TokenSecret)

        Dim request = fullRequest.CreateHttpWebRequest
        request.ContentLength = 0
        Try
            Dim response = request.GetResponse
            Dim data = New IO.StreamReader(response.GetResponseStream).ReadToEnd
            Return data

        Catch ex As Net.WebException
            Dim response = ex.Response
            Dim data = New IO.StreamReader(response.GetResponseStream).ReadToEnd
            Throw New Exception(data, ex)
        End Try
    End Function

    ''' <summary>
    ''' This method performs a general Netflix request for the RESTful resource specified and returns the results as parsed XML.
    ''' </summary>
    ''' <param name="resource">
    ''' The RESTful resource being requested.
    ''' </param>
    ''' <returns>
    ''' An XElement object containing the parsed XML results of the RESTful resource request.
    ''' </returns>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Public Function RequestXmlResource(ByVal resource As RestCall) As XElement
        Return XElement.Parse(RequestResource(resource))
    End Function

    ''' <summary>
    ''' This method performs a general Netflix request, signed with a user's token, for the RESTful resource specified and returns the results as parsed XML.
    ''' </summary>
    ''' <param name="resource">
    ''' The RESTful resource being requested.
    ''' </param>
    ''' <param name="accessToken">
    ''' The current user's Access Token.
    ''' </param>
    ''' <returns>
    ''' An XElement object containing the parsed XML results of the RESTful resource request.
    ''' </returns>
    ''' <remarks>
    ''' ?? Under what conditions does this function work when its under-loaded cousin does not? ??
    ''' </remarks>
    Public Function RequestXmlResource(ByVal resource As RestCall, ByVal accessToken As IAccessToken) As XElement
        Return XElement.Parse(RequestResource(resource, accessToken))
    End Function

    ''' <summary>
    ''' This returns a Catalog object, which can subsequently be used to search the Netflix catalog.
    ''' </summary>
    ''' <returns>
    ''' 
    ''' </returns>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Public ReadOnly Property Catalog() As Catalog
        Get
            Return m_Catalog
        End Get
    End Property

End Class
